#include "pch.h"
#include "AsyncLibImpl.h"
#include "Threadpool/ThreadpoolWork.h"
#include "Threadpool/ThreadpoolTimer.h"

namespace AsyncLib
{

static_assert(ATID_MAIN == 1);

thread_local intptr_t g_nAtid;

CAsyncLib::CAsyncLib() : m_status(Exited)
{
}

CAsyncLib::~CAsyncLib()
{
	assert(m_status == Exited);
}

void CAsyncLib::Init(ATID atidMax)
{
	std::unique_lock lock(m_mutex);
	assert(m_status == Exited);

	if (m_status != Exited)
		return;

	m_status = Running;
	SetInTaskThread(ATID_MAIN);
	InitTaskThreads(atidMax);
	InitThreadpools();
}

void CAsyncLib::Exit(bool bWaitTasks)
{
	if (bWaitTasks)
		WaitForAllTasks();

	std::unique_lock lock(m_mutex);
	assert(m_status == Running);

	if (m_status != Running)
		return;

	m_status = Exiting;
	lock.unlock();
	ExitTaskThreads();
	ExitThreadpools();
	ProcessCallbacks();
}

void CAsyncLib::WaitForAllTasks()
{
}

void CAsyncLib::InitTaskThreads(ATID atidMax)
{
}

void CAsyncLib::ExitTaskThreads()
{
}

void CAsyncLib::InitThreadpools()
{
	m_pThreadpoolWork = std::make_unique<CThreadpoolWork>();
	m_pThreadpoolWork->Init();
	m_pThreadpoolTimer = std::make_unique<CThreadpoolTimer>();
	m_pThreadpoolTimer->Init();
}

void CAsyncLib::ExitThreadpools()
{
	m_pThreadpoolWork->Stop();
	m_pThreadpoolTimer->Stop();

	m_pThreadpoolWork->Exit();
	m_pThreadpoolWork = nullptr;
	m_pThreadpoolTimer->Exit();
	m_pThreadpoolTimer = nullptr;
}

void CAsyncLib::PostTask(ATID atid, std::function<void()>&& fnTask)
{
	assert(atid);
	std::shared_lock lock(m_mutex);

	if (IsRunning() && fnTask)
		m_pThreadpoolWork->PostTask(std::move(fnTask));
}

void CAsyncLib::PostDelayedTask(UINT nMilliseconds, std::function<void()>&& fnTask)
{
	std::shared_lock lock(m_mutex);

	if (IsRunning() && fnTask)
		m_pThreadpoolTimer->AddTask(nMilliseconds, std::move(fnTask));
}

void CAsyncLib::WaitForAsync(HANDLE handle, UINT nMilliseconds, std::function<void(DWORD)>&& fnCallback)
{
}

bool CAsyncLib::IsInTaskThread(ATID atid) const
{
	assert(atid);
	return g_nAtid == atid || m_status == Exited;
}

bool CAsyncLib::IsInThreadPool() const
{
	return IsInTaskThread(ATID_TP);
}

void CAsyncLib::SetInTaskThread(ATID atid)
{
	assert(atid);
	g_nAtid = atid;
}

void CAsyncLib::SetInThreadPool()
{
	SetInTaskThread(ATID_TP);
}

ATID CAsyncLib::InnerGetAtid() const
{
	return ATID(g_nAtid);
}

void CAsyncLib::InnerPostTask(ATID atid, std::function<void()>&& fnTask)
{
}

void CAsyncLib::ProcessCallbacks()
{
	std::unique_lock lock(m_mutex);
	m_status = Exited;
}

std::shared_ptr<ITimerTask> CAsyncLib::CreateTimerTask(bool bUITimer)
{
	return nullptr;
}

std::shared_ptr<IFileTask> CAsyncLib::CreateFileTask(HANDLE hFile)
{
	return nullptr;
}

} // namespace AsyncLib
